package com.senlingspace.framework.interceptor;

import com.alibaba.fastjson2.JSON;
import com.senlingspace.common.core.domain.AjaxResult;
import com.senlingspace.common.core.redis.RedisCache;
import com.senlingspace.common.utils.JwtUtilExt;
import com.senlingspace.framework.config.properties.ProtectUriProperties;
import com.senlingspace.framework.security.context.SecurityContextHolderExt;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Objects;
import java.util.regex.Pattern;

/**
 * 微信小程序认证拦截器
 *
 * @author lebronjames
 */
@Slf4j
@AllArgsConstructor
@Component
public class WeChatAuthInterceptor implements HandlerInterceptor {

    /**
     * 微信小程序登录
     */
    private final static String CUSTOMER_LOGIN_KEY = "wmp_customer_login:";

    private final ProtectUriProperties protectUriProperties;
    private final RedisCache redisCache;


    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        String uri = request.getRequestURI();
        log.info("当前请求uri = {}", uri);

        // 匹配当前请求是否在名单内
        boolean uriMatched = protectUriProperties.getUris()
                .stream()
                .anyMatch(protectedUri -> {
                    // 如果是以 /** 结尾的 URI，转换为正则表达式进行匹配
                    if (protectedUri.endsWith("/**")) {
                        String regex = protectedUri.substring(0, protectedUri.length() - 3) + ".*";
                        return Pattern.matches(regex, uri);
                    }
                    // 如果是以 /* 结尾的 URI，匹配单层路径
                    if (protectedUri.endsWith("/*")) {
                        String regex = protectedUri.substring(0, protectedUri.length() - 2) + "/[^/]+";
                        return Pattern.matches(regex, uri);
                    }
                    // 否则进行直接匹配
                    return uri.equals(protectedUri);
                });

        if (uriMatched) {
            log.info("当前请求 {} 在名单内，需验证Token！", uri);

            String token = request.getHeader("Wx-Authorization");

            if (StringUtils.isBlank(token)) {
                log.info("{} 请求，Token为空！", uri);
                return response401(response, "令牌不能为空！");
            }

            if (!JwtUtilExt.isValidity(token)) {
                log.info("{} 令牌不合规！", token);
                return response401(response, "令牌无效，请重新登录！");
            }

            if (!JwtUtilExt.isExpire(token)) {
                log.info("{} 令牌失效！", token);
                return response401(response, "令牌失效，请重新登录！");
            }

            String key = CUSTOMER_LOGIN_KEY.concat(JwtUtilExt.getPhone(token));
            if (!redisCache.hasKey(key)) {
                log.info("用户 {} 令牌失效！", token);
                return response401(response, "令牌失效，请重新登录！");
            }

            Object cacheToken = redisCache.getCacheObject(key);
            if (!Objects.equals(token, cacheToken)) {
                log.info("{} 令牌比对不合规！", token);
                return response401(response, "令牌无效，请重新登录！");
            }
        }
        return true;
    }

    private static boolean response401(HttpServletResponse response, String msg) throws IOException {
        response.setStatus(HttpStatus.SC_UNAUTHORIZED);
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().write(JSON.toJSONString(AjaxResult.error(HttpStatus.SC_UNAUTHORIZED, msg)));
        return false;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        SecurityContextHolderExt.remove();
    }

}
